package edu.ccut.saturn.studio.wfg.part;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.ReconnectRequest;
import org.eclipse.gef.tools.DirectEditManager;
import org.eclipse.jface.viewers.TextCellEditor;

import edu.ccut.saturn.studio.logic.model.BasicShape;
import edu.ccut.saturn.studio.wfg.command.ConnectionCreateCommand;
import edu.ccut.saturn.studio.wfg.command.ConnectionReconnectCommand;
import edu.ccut.saturn.studio.wfg.command.OpenDialogCommand;
import edu.ccut.saturn.studio.wfg.figure.SaturnFigure;
import edu.ccut.saturn.studio.wfg.model.Connection;
import edu.ccut.saturn.studio.wfg.model.Shape;
import edu.ccut.saturn.studio.wfg.policy.SaturnDirectEditPolicy;

public class ShapeEditPart extends AbstractGraphicalEditPart implements
		PropertyChangeListener, NodeEditPart {

	private ConnectionAnchor anchor;
	protected DirectEditManager manager;

	public void activate() {
		if (!isActive()) {
			super.activate();
			((BasicShape) getModel()).addPropertyChangeListener(this);
		}
	}

	protected void createEditPolicies() {

		installEditPolicy(EditPolicy.COMPONENT_ROLE,
				new ShapeComponentEditPolicy());

		installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE,
				new SaturnDirectEditPolicy());
		installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE,
				new GraphicalNodeEditPolicy() {

					protected Command getConnectionCompleteCommand(
							CreateConnectionRequest request) {

						ConnectionCreateCommand cmd = (ConnectionCreateCommand) request
								.getStartCommand();
						cmd.setTarget((Shape) getHost().getModel());
						return cmd;

					}

					protected Command getConnectionCreateCommand(
							CreateConnectionRequest request) {
						Shape source = (Shape) getHost().getModel();
						int style = ((Integer) request.getNewObjectType())
								.intValue();
						ConnectionCreateCommand cmd = new ConnectionCreateCommand(
								source, style);
						request.setStartCommand(cmd);
						return cmd;

					}

					protected Command getReconnectSourceCommand(
							ReconnectRequest request) {
						Connection conn = (Connection) request
								.getConnectionEditPart().getModel();
						Shape newSource = (Shape) getHost().getModel();
						ConnectionReconnectCommand cmd = new ConnectionReconnectCommand(
								conn);
						cmd.setNewSource(newSource);
						return cmd;
					}

					protected Command getReconnectTargetCommand(
							ReconnectRequest request) {
						Connection conn = (Connection) request
								.getConnectionEditPart().getModel();
						Shape newTarget = (Shape) getHost().getModel();
						ConnectionReconnectCommand cmd = new ConnectionReconnectCommand(
								conn);
						cmd.setNewTarget(newTarget);
						return cmd;
					}
				});
	}

	@Override
	public void performRequest(Request req) {

		if (req.getType() == RequestConstants.REQ_DIRECT_EDIT) {
			if (manager == null) {
				Figure figure = (Figure) getFigure();
				manager = new NodeDirectEditManager(this, TextCellEditor.class,
						new NodeCellEditorLocator(figure));
			}
			manager.show(); 
		}
		if (req.getType() == RequestConstants.REQ_OPEN) {

			getViewer().getEditDomain().getCommandStack().execute(
					new OpenDialogCommand(((Shape) getModel()).getDialog(),
							(Shape) getModel()));
		}
	}

	protected IFigure createFigure() {
		Object model = super.getModel();

		if (model instanceof Shape) {
			Shape shape = (Shape) model;
			return shape.getFigure();
		}

		return null;
	}

	public void deactivate() {
		if (isActive()) {
			super.deactivate();
			((BasicShape) getModel()).removePropertyChangeListener(this);
		}
	}

	private Shape getCastedModel() {
		return (Shape) getModel();
	}
    /**
     * 更改锚点的地方。
     * @return
     */
	protected ConnectionAnchor getConnectionAnchor() {
		if (anchor == null) {
			if (getModel() instanceof Shape) {
				anchor = new BorderAnchor(getFigure());
			} else {
				throw new IllegalArgumentException("unexpected model");
			}
		}
		return anchor;
	}

	protected List<Connection> getModelSourceConnections() {
		return getCastedModel().getSourceConnections();
	}

	protected List<Connection> getModelTargetConnections() {
		return getCastedModel().getTargetConnections();
	}

	public ConnectionAnchor getSourceConnectionAnchor(
			ConnectionEditPart connection) {
		return getConnectionAnchor();
	}

	public ConnectionAnchor getSourceConnectionAnchor(Request request) {
		return getConnectionAnchor();
	}

	public ConnectionAnchor getTargetConnectionAnchor(
			ConnectionEditPart connection) {
		return getConnectionAnchor();
	}

	public ConnectionAnchor getTargetConnectionAnchor(Request request) {
		return getConnectionAnchor();
	}

	public void propertyChange(PropertyChangeEvent evt) {
		String prop = evt.getPropertyName();
		if (Shape.SIZE_PROP.equals(prop) || Shape.LOCATION_PROP.equals(prop)
				|| Shape.NAME_PROP.equals(prop)) {
			refreshVisuals();
		} else if (Shape.SOURCE_CONNECTIONS_PROP.equals(prop)) {
			refreshSourceConnections();
		} else if (Shape.TARGET_CONNECTIONS_PROP.equals(prop)) {
			refreshTargetConnections();
		}
	}

	protected void refreshVisuals() {
		Rectangle bounds = new Rectangle(getCastedModel().getLocation().x,getCastedModel().getLocation().y,
				-1,-1);

		IFigure figure = super.getFigure();

		((GraphicalEditPart) getParent()).setLayoutConstraint(this, figure,
				bounds);

		if (figure instanceof SaturnFigure) {
			Object model = super.getModel();

			if (model instanceof Shape) {
				Shape shape = (Shape) model;
				SaturnFigure saturnFigure = (SaturnFigure) figure;

				saturnFigure.setName(shape.getName());
			}
		}
	}
}